#ifndef alvo_hh__included__
#define alvo_hh__included__

#include <map>
//~ #include <list>
#include <vector>
//~ #include <string>

typedef enum {AC_NONE,AC_GRP,AC_LIST,AC_LAZY,AC_STRING,AC_INTEGER,AC_SYM,AC_EVAL} AC;

using namespace std;

//~ class A_CONT;
//~ class A_INT;
//~ class A_EVAL;
//~ class AH_CONT;

class ALVO {
public:
	AC ac;
};

class A_CONT_TAG {
public: virtual void add(ALVO*)=0;
	vector<ALVO*> items;
};

class ALVO_runtime;
#if 0
template <typename T, AC pac>
class __Abb : public ALVO, public A_CONT_TAG  {
public:
	__Abb() { ac = pac;}
	vector<ALVO*> items;
public: virtual void add(ALVO*);
};
class A_LIST : public __Abb<int,   AC_LIST> {};
class A_GRP  : public __Abb<int,   AC_GRP>  {};
class A_LAZY : public __Abb<int,   AC_LAZY> {};
#else
class A_LIST : public ALVO, public A_CONT_TAG {
public:
	A_LIST() { ac = AC_LIST; }
	//~ vector<ALVO*> items;
public: virtual void add(ALVO*);
public: virtual ALVO* eval(ALVO_runtime&);
};
class A_GRP  : public ALVO, public A_CONT_TAG {
public:
	A_GRP() { ac = AC_GRP; }
	//~ vector<ALVO*> items;
public: virtual void add(ALVO*);
public: virtual ALVO* eval(ALVO_runtime&);
};
class A_LAZY : public ALVO, public A_CONT_TAG {
public:
	A_LAZY() { ac = AC_LAZY; }
	//~ vector<ALVO*> items;
public: virtual void add(ALVO*);
public: virtual ALVO* eval(ALVO_runtime&);
};
#endif

class AH_CONT {
public:
	bool valid;
	A_CONT_TAG*c;
};

//~ class A_STR  : public ALVO {
//~ public:
	//~ A_STR() { ac = AC_STRING ;}
	//~ char *m;
//~ };
template <typename T, AC pac>
class __Aaa : public ALVO {
public:
	__Aaa() { ac = pac;}
	T m;
};
class A_INT  : public __Aaa<int,   AC_INTEGER> {};
class A_EVAL : public __Aaa<char*, AC_EVAL>    {};
class A_STR  : public __Aaa<char*, AC_STRING>  {};
class A_SYM  : public __Aaa<char*, AC_SYM>     {};

class ALVO_C {
public:
	A_GRP  *group();
	A_LIST *list ();
	A_LAZY *lazy ();
	
	A_GRP  *group(AH_CONT*);
	A_LIST *list (AH_CONT*);
	A_LAZY *lazy (AH_CONT*);
	
	A_STR  *stringular (char*,  AH_CONT*);
	A_INT  *int_       (int,    AH_CONT*);
	A_INT  *int_       (char*,  AH_CONT*);
	A_SYM  *symbol     (char*,  AH_CONT*);
	A_EVAL *eval       (char*,  AH_CONT*);
};

//should be namespace
class ALVO_X {
public:
	AH_CONT *cont(A_CONT_TAG&);
};

struct ltstr{
  bool operator()(const char* s1, const char* s2) const{
    return strcmp(s1, s2) < 0;
  }
};

class ALVO_runtime {
	map<char*,ALVO*,ltstr> fns;
	typedef map<char*,ALVO*,ltstr>::iterator fns_iter;
	vector<ALVO*> items;
	static ALVO_runtime *base;
	//~ ALVO* first;
public:
	static ALVO_C C;
	static ALVO_X X;
	//
	ALVO_runtime *parent;
	//
	void eval(A_EVAL*);
	void push(ALVO*);
	ALVO *ALVO_runtime::pop();
};

namespace AlvoM {
void print_int(int T);
}

void  enter_frame (ALVO_runtime &frame, A_LAZY &al);
ALVO* eval        (ALVO_runtime &frame, ALVO   &i);

#endif
